#include "Restaurant.h"
#include <string>
#include <sstream>

const int NEW_ORDER=1;
const int CHANGE_ORDER=2;



// FOR DEBUG ONLY
#define	DEBUG	0

void inline debugPrint(string msg){
	if (DEBUG){
		cout << msg;
	}
}

// HARD-CODED GLOBAL CONSTANTS
const int INIT_ARR_SIZE	=	8;
const int EXPAND_VALUE	=	8; 

void debugPrint(string msg);

using namespace std;

Restaurant::Restaurant(void){
	customers = new Customer*[INIT_ARR_SIZE];
	orders = new Order*[INIT_ARR_SIZE];
	arrSize = INIT_ARR_SIZE;
	arrIndex = 0;

}

Restaurant::~Restaurant(void){
	for (int i = 0; i < arrIndex; i++){
		delete customers[i];
		if (orders[i] != NULL){
			delete orders[i];
		}
	}
}


//returns -1 on new() fail
int inline Restaurant::handleArray(){

	if (this->arrIndex < this->arrSize){
		//there is still room in the current array
		return 0;
	}
	else if (this->arrIndex == this->arrSize){
		// create a bigger array and copy the pointers from the old array
		debugPrint("array allocation needed");
		Customer** newCustomersArr = new Customer*[this->arrSize + EXPAND_VALUE];
		if (newCustomersArr == NULL){
			return -1;
		}
		Order** newOrdersArr = new Order*[this->arrSize + EXPAND_VALUE];
		if (newOrdersArr == NULL){
			delete[] newCustomersArr;
			return -1;
		}
		for (int i = 0; i < this->arrSize; i++){
			newCustomersArr[i] = customers[i];
			newOrdersArr[i] = orders[i];
		}

		this->arrSize += EXPAND_VALUE;

		//free the mem. allocated for the old array (arr. of pointers)
		delete[] this->customers;
		delete[] this->orders;
		this->customers = newCustomersArr;
		this->orders = newOrdersArr;
		return 0;
	}
	else {
		// we should never enter this condition
		debugPrint("ERROR: Restaurant::handleArray(): (this->arrIndex + 1) < this->arrSize\n"); 
	}

	return 0;	
}

//returns -1 if fails
int Restaurant::addCustomerToArray(Customer& customer){
	int ret = handleArray();
	if (ret == -1){
		// handleArray() failed - return -1
		return -1;
	}
	customers[arrIndex] = &customer;
	orders[arrIndex] = NULL; //new Order();
	arrIndex++;

	return 0;
}

int Restaurant::addCustomer(const string& name){
	Customer* customer = new Customer(name);
	//check for mem. alloc. failure
	if (customer == NULL){
		return -1;
	}
	int retVal = addCustomerToArray(*customer);
	// check if addCustomerToArray failed
	if (retVal == -1) { 
		return -1;
	}

	return 0;
}

string Restaurant::removeCustomer(int cIndex){
	if (cIndex < 0 || cIndex >= arrIndex){
		return "index out of bounds\n";
	}

	delete customers[cIndex];
	if (orders[cIndex] != NULL){
		delete orders[cIndex];
		orders[cIndex] = NULL;
	}
	// left shift
	for (int i = cIndex; i < arrIndex-1; i++){
		customers[i] = customers[i+1];
		orders[i] = orders[i+1];
	}
	arrIndex--;

	return "customer removed.\n";
}

string Restaurant::getCustomers() const {
	ostringstream sstr;
	sstr << endl << "Customers:" << endl << endl;
	for (int i = 0; i < arrIndex; i++){
		sstr << i << ")\t" << customers[i]->toString() << endl;
	}

	return sstr.str();
}

string Restaurant::getOrders() const {
	ostringstream sstr;
	sstr << endl <<  "Orders:" << endl << endl;
	for (int i = 0; i < arrIndex; i++){
		if (orders[i] != NULL){
			sstr << i << ")\t" << orders[i]->toString() << endl;
		}
		else {
			sstr << i << ")\t" << "no order" << endl;
		}
	}

	return sstr.str();
}

/// returns "ERR" on failure
string Restaurant::handleOrder(int usage,int index, const string& drink, const string& first, const string& main, const string& last){
	if ((index < 0) || (index >= arrIndex)){
		return "order index out of bounds\n";
	}
	if (usage==NEW_ORDER){
		if (orders[index] != NULL){
			return "order exist for this client\n";
		}
		Order* newOrd = new Order(drink,first,main,last);
		if (newOrd == NULL) {
			return "ERR";
		}
		orders[index] = newOrd;
		return "order added\n";
	}
	
	if (usage==CHANGE_ORDER){
		if (orders[index] == NULL) {
				return "order does not exist for this client\n";
			} else {
				// editing existing order
				Order& ord = *orders[index];
		
				if (!drink.empty()){
					if(drink.compare("clear")==0)
						ord.clearDrink();
					else
						ord.setDrink(drink);
				}

				if (!first.empty()){
					if(first.compare("clear")==0)
						ord.clearFirst();
					else
						ord.setFirst(first);
				}

				if (!main.empty()){
					if(main.compare("clear")==0)
						ord.clearMain();
					else
						ord.setMain(main);
				}

				if (!last.empty()){
					if(last.compare("clear")==0)
						ord.clearLast();
					else
						ord.setLast(last);
				}
			}
			return "order changed\n";
		}

	//we are not supposed to get here - debug only
	return "error: illegal param. in handleOrder() call.\n";
}

// returns "ERR" on failure
string Restaurant::takeOrder(int index, const string& drink, const string& first, const string& main, const string& last){
	return handleOrder(NEW_ORDER,index,drink,first,main,last);
}

// returns "ERR" on failure
string Restaurant::changeOrder(int index, const string& drink, const string& first, const string& main, const string& last){
	return handleOrder(CHANGE_ORDER,index,drink,first,main,last);
}


string Restaurant::removeOrder(int cIndex){
	if (cIndex < 0 || cIndex >= arrIndex){
		return "index out of bounds\n";
	}

	if (orders[cIndex]==NULL){
		return "this client has no order\n";
	}

	delete orders[cIndex];
	orders[cIndex]=NULL;

	return "order removed.\n";
}

bool Restaurant::checkOrderExists(int index){
	if (index < 0 || index >= arrIndex){
		return false;
	}
	if (orders[index]==NULL) {
		return false;
	}
	return true;
}

bool Restaurant::checkCustomerExists(int index){
		if (index < 0 || index >= arrIndex){
		return false;
	}
	return true;
}